package CPU.rv64_5stage

import chisel3.util._

object RV32I_ALUInstr extends HasInstrType {
  def ADDI    = BitPat("b????????????_?????_000_?????_0010011")
  def SLLI    = BitPat("b000000??????_?????_001_?????_0010011")
  def SLTI    = BitPat("b????????????_?????_010_?????_0010011")
  def SLTIU   = BitPat("b????????????_?????_011_?????_0010011")
  def XORI    = BitPat("b????????????_?????_100_?????_0010011")
  def SRLI    = BitPat("b000000??????_?????_101_?????_0010011")
  def ORI     = BitPat("b????????????_?????_110_?????_0010011")
  def ANDI    = BitPat("b????????????_?????_111_?????_0010011")
  def SRAI    = BitPat("b010000??????_?????_101_?????_0010011")

  def ADD     = BitPat("b0000000_?????_?????_000_?????_0110011")
  def SLL     = BitPat("b0000000_?????_?????_001_?????_0110011")
  def SLT     = BitPat("b0000000_?????_?????_010_?????_0110011")
  def SLTU    = BitPat("b0000000_?????_?????_011_?????_0110011")
  def XOR     = BitPat("b0000000_?????_?????_100_?????_0110011")
  def SRL     = BitPat("b0000000_?????_?????_101_?????_0110011")
  def OR      = BitPat("b0000000_?????_?????_110_?????_0110011")
  def AND     = BitPat("b0000000_?????_?????_111_?????_0110011")
  def SUB     = BitPat("b0100000_?????_?????_000_?????_0110011")
  def SRA     = BitPat("b0100000_?????_?????_101_?????_0110011")

  def AUIPC   = BitPat("b????????????????????_?????_0010111")
  def LUI     = BitPat("b????????????????????_?????_0110111")

  val table = Array(
    ADDI           -> List(InstrI, FuType.alu, ALUOpType.add),
    SLLI           -> List(InstrI, FuType.alu, ALUOpType.sll),
    SLTI           -> List(InstrI, FuType.alu, ALUOpType.slt),
    SLTIU          -> List(InstrI, FuType.alu, ALUOpType.sltu),
    XORI           -> List(InstrI, FuType.alu, ALUOpType.xor),
    SRLI           -> List(InstrI, FuType.alu, ALUOpType.srl),
    ORI            -> List(InstrI, FuType.alu, ALUOpType.or ),
    ANDI           -> List(InstrI, FuType.alu, ALUOpType.and),
    SRAI           -> List(InstrI, FuType.alu, ALUOpType.sra),

    ADD            -> List(InstrR, FuType.alu, ALUOpType.add),
    SLL            -> List(InstrR, FuType.alu, ALUOpType.sll),
    SLT            -> List(InstrR, FuType.alu, ALUOpType.slt),
    SLTU           -> List(InstrR, FuType.alu, ALUOpType.sltu),
    XOR            -> List(InstrR, FuType.alu, ALUOpType.xor),
    SRL            -> List(InstrR, FuType.alu, ALUOpType.srl),
    OR             -> List(InstrR, FuType.alu, ALUOpType.or ),
    AND            -> List(InstrR, FuType.alu, ALUOpType.and),
    SUB            -> List(InstrR, FuType.alu, ALUOpType.sub),
    SRA            -> List(InstrR, FuType.alu, ALUOpType.sra),

    AUIPC          -> List(InstrU, FuType.alu, ALUOpType.add),
    LUI            -> List(InstrU, FuType.alu, ALUOpType.add)
  )
}

object RV32I_BRUInstr extends HasInstrType {
  def JAL   = BitPat("b????????????????????_?????_1101111")
  def JALR  = BitPat("b????????????_?????_000_?????_1100111")

  def BNE   = BitPat("b???????_?????_?????_001_?????_1100011")
  def BEQ   = BitPat("b???????_?????_?????_000_?????_1100011")
  def BLT   = BitPat("b???????_?????_?????_100_?????_1100011")
  def BGE   = BitPat("b???????_?????_?????_101_?????_1100011")
  def BLTU  = BitPat("b???????_?????_?????_110_?????_1100011")
  def BGEU  = BitPat("b???????_?????_?????_111_?????_1100011")

  val table = Array(
    JAL -> List(InstrJ, FuType.bru, ALUOpType.jal),
    JALR -> List(InstrI, FuType.bru, ALUOpType.jalr),

    BEQ -> List(InstrB, FuType.bru, ALUOpType.beq),
    BNE -> List(InstrB, FuType.bru, ALUOpType.bne),
    BLT -> List(InstrB, FuType.bru, ALUOpType.blt),
    BGE -> List(InstrB, FuType.bru, ALUOpType.bge),
    BLTU -> List(InstrB, FuType.bru, ALUOpType.bltu),
    BGEU -> List(InstrB, FuType.bru, ALUOpType.bgeu)
  )
}

object RV32I_LSUInstr extends HasInstrType {
  def LB      = BitPat("b????????????_?????_000_?????_0000011")
  def LH      = BitPat("b????????????_?????_001_?????_0000011")
  def LW      = BitPat("b????????????_?????_010_?????_0000011")
  def LBU     = BitPat("b????????????_?????_100_?????_0000011")
  def LHU     = BitPat("b????????????_?????_101_?????_0000011")
  def SB      = BitPat("b???????_?????_?????_000_?????_0100011")
  def SH      = BitPat("b???????_?????_?????_001_?????_0100011")
  def SW      = BitPat("b???????_?????_?????_010_?????_0100011")

  val table = Array(
    LB             -> List(InstrI, FuType.lsu, LSUOpType.lb ),
    LH             -> List(InstrI, FuType.lsu, LSUOpType.lh ),
    LW             -> List(InstrI, FuType.lsu, LSUOpType.lw ),
    LBU            -> List(InstrI, FuType.lsu, LSUOpType.lbu),
    LHU            -> List(InstrI, FuType.lsu, LSUOpType.lhu),
    SB             -> List(InstrS, FuType.lsu, LSUOpType.sb ),
    SH             -> List(InstrS, FuType.lsu, LSUOpType.sh ),
    SW             -> List(InstrS, FuType.lsu, LSUOpType.sw)
  )
}

object RV64IInstr extends HasInstrType {
  def ADDIW   = BitPat("b???????_?????_?????_000_?????_0011011")
  def SLLIW   = BitPat("b0000000_?????_?????_001_?????_0011011")
  def SRLIW   = BitPat("b0000000_?????_?????_101_?????_0011011")
  def SRAIW   = BitPat("b0100000_?????_?????_101_?????_0011011")
  def SLLW    = BitPat("b0000000_?????_?????_001_?????_0111011")
  def SRLW    = BitPat("b0000000_?????_?????_101_?????_0111011")
  def SRAW    = BitPat("b0100000_?????_?????_101_?????_0111011")
  def ADDW    = BitPat("b0000000_?????_?????_000_?????_0111011")
  def SUBW    = BitPat("b0100000_?????_?????_000_?????_0111011")

  def LWU     = BitPat("b???????_?????_?????_110_?????_0000011")
  def LD      = BitPat("b???????_?????_?????_011_?????_0000011")
  def SD      = BitPat("b???????_?????_?????_011_?????_0100011")

  val table = Array(
    ADDIW          -> List(InstrI, FuType.alu, ALUOpType.addw),
    SLLIW          -> List(InstrI, FuType.alu, ALUOpType.sllw),
    SRLIW          -> List(InstrI, FuType.alu, ALUOpType.srlw),
    SRAIW          -> List(InstrI, FuType.alu, ALUOpType.sraw),
    SLLW           -> List(InstrR, FuType.alu, ALUOpType.sllw),
    SRLW           -> List(InstrR, FuType.alu, ALUOpType.srlw),
    SRAW           -> List(InstrR, FuType.alu, ALUOpType.sraw),
    ADDW           -> List(InstrR, FuType.alu, ALUOpType.addw),
    SUBW           -> List(InstrR, FuType.alu, ALUOpType.subw),

    LWU            -> List(InstrI, FuType.lsu, LSUOpType.lwu),
    LD             -> List(InstrI, FuType.lsu, LSUOpType.ld ),
    SD             -> List(InstrS, FuType.lsu, LSUOpType.sd)
  )
}

object RVZicsrInstr extends HasInstrType {
  def CSRRW   = BitPat("b????????????_?????_001_?????_1110011")
  def CSRRS   = BitPat("b????????????_?????_010_?????_1110011")
  def CSRRC   = BitPat("b????????????_?????_011_?????_1110011")
  def CSRRWI  = BitPat("b????????????_?????_101_?????_1110011")
  def CSRRSI  = BitPat("b????????????_?????_110_?????_1110011")
  def CSRRCI  = BitPat("b????????????_?????_111_?????_1110011")

  val table = Array(
    CSRRW          -> List(InstrI, FuType.csr, CSROpType.wrt),
    CSRRS          -> List(InstrI, FuType.csr, CSROpType.set),
    CSRRC          -> List(InstrI, FuType.csr, CSROpType.clr),
    CSRRWI         -> List(InstrI, FuType.csr, CSROpType.wrti),
    CSRRSI         -> List(InstrI, FuType.csr, CSROpType.seti),
    CSRRCI         -> List(InstrI, FuType.csr, CSROpType.clri)
  )
}

object RVIInstr extends HasInstrType{
  val DecodeDefault = List(InstrN,FuType.csr,ALUOpType.add)
  val table = RV32I_ALUInstr.table ++ RV32I_BRUInstr.table ++
              RV32I_LSUInstr.table ++ RV64IInstr.table ++
              RVZicsrInstr.table
}
